﻿//========================================================= 
/**@file DynamicLibraryCmdDriver.h
 * @brief 从动态库中加载的驱动
 * 
 * @date 2016-10-04   15:07:17
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_DYNAMICLIBRARYCMDDRIVER_H_
#define _LIBZHOUYB_DYNAMICLIBRARYCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../tools/DynamicDriverLinker.h"
using zhou_yb::application::tools::DynamicDriverLinker;

#include "../../tools/ICmdDriver.h"
using zhou_yb::application::tools::DLL_FUNCTION(CreateObject);
using zhou_yb::application::tools::DLL_FUNCTION(DestoryObject);
using zhou_yb::application::tools::DLL_FUNCTION(LookUp);

#include "../../tools/IConverter.h"
using zhou_yb::application::tools::ConverterInvoker;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// 驱动ICommandDriver接口封装
class CommandDriverInvoker : 
    public ICommandDriver,
    public LoggerBehavior,
    public RefObject
{
protected:
    ConverterInvoker _cvt;
public:
    virtual ~CommandDriverInvoker()
    {
        Dispose();
    }
    bool Load(const char* drv, const char* entrypoint)
    {
        LOG_FUNC_NAME();
        if(_cvt.IsValid())
        {
            _cvt.Dispose();
        }
        string ep = _strput(entrypoint);
        ep += "_TransmitCommand";
        return _cvt.Load(drv, ep.c_str());
    }
    bool IsValid()
    {
        return _cvt.IsValid();
    }
    void Dispose()
    {
        _cvt.Dispose();
    }
    virtual bool TransmitCommand(const ByteArray& sCmd, const ByteArray& send, ByteBuilder& recv)
    {
        if(!_cvt.IsValid())
            return false;
        string sRlt;
        if(!_cvt.Convert(sCmd.GetString(), sRlt, send.GetString()))
            return false;
        recv += sRlt.c_str();
        return true;
    }
};
//--------------------------------------------------------- 
/// 适配ICommandDriver接口封装成CommandCollection的适配器
template<class TArgParser>
class CommandDriverToCollectionAdapter :
    public BaseDevAdapterBehavior<ICommandDriver>,
    public CommandCollection
{
protected:
    TArgParser _parser;
    list_t<CommandDriverScriptActuator<TArgParser> > _scriptCollection;
public:
    virtual void SelectDevice(const Ref<ICommandDriver>& dev)
    {
        ReleaseDevice();
        BaseDevAdapterBehavior::SelectDevice(dev);
        if(!BaseDevAdapterBehavior::IsValid())
            return;
        // 枚举命令
        ByteBuilder rlt(64);
        if(!_pDev->TransmitCommand("EnumCommand", "", rlt))
            return;
        StringArguments arg;
        _parser.Parse(rlt.GetString(), arg);
        list_t<string> cmdNames;
        arg.Get("CMD", cmdNames);

        list_t<string>::iterator itr;
        Ref<ComplexCommand> complexCmd;
        for(itr = cmdNames.begin();itr != cmdNames.end(); ++itr)
        {
            _scriptCollection.push_back();

            CommandDriverScriptActuator<TArgParser>& script = _scriptCollection.back();
            Ref<ICommandDriver> drv = dev;
            complexCmd = script.Script(drv, (*itr).c_str());

            Registe(complexCmd);
        }
    }
    virtual void ReleaseDevice()
    {
        BaseDevAdapterBehavior::ReleaseDevice();

        CommandCollection::Clear();
        _scriptCollection.clear();
    }
};
//--------------------------------------------------------- 
class CommandCollectionInvoker : 
    public CommandCollection,
    public LoggerBehavior
{
protected:
    size_t _hInstance;
    DynamicDriverLinker _drv;

    DLL_FUNCTION(CreateObject) _CreateObject;
    DLL_FUNCTION(DestoryObject) _DestoryObject;
    DLL_FUNCTION(LookUp) _LookUp;
public:
    CommandCollectionInvoker()
    {
        _hInstance = 0;

        _CreateObject = NULL;
        _DestoryObject = NULL;
        _LookUp = NULL;
    }
    virtual ~CommandCollectionInvoker()
    {
        Dispose();
    }
    bool Load(const char* drv, const char* entrypoint)
    {
        LOG_FUNC_NAME();
        Dispose();
        LOGGER(_log << "Load Library:<" << _strput(drv) << ">,EntryPoint:<" << _strput(entrypoint) << ">\n");
        DynamicDriverLinker loader;
        if(!loader.Load(drv))
        {
            LOGGER(_log.WriteLine("加载驱动失败"));
            return false;
        }
        string spaceName = _strput(entrypoint);
        if(spaceName.length() > 0)
            spaceName += "_";
        
        string drvname = spaceName;
        drvname += "CreateObject";
        _CreateObject = loader.Get<DLL_FUNCTION(CreateObject)>(drvname.c_str());
        LOGGER(_log << "SpaceName:<" << drvname << ">\n");
        LOGGER(_log << "CreateObject:<" << _hex(_CreateObject) << ">\n");
        if(_CreateObject == NULL)
        {
            LOGGER(_log.WriteLine("CreateObject is NULL."));
            return false;
        }

        drvname = spaceName;
        drvname += "DestoryObject";
        _DestoryObject = loader.Get<DLL_FUNCTION(DestoryObject)>(drvname.c_str());
        LOGGER(_log << "SpaceName:<" << drvname << ">\n");
        LOGGER(_log << "DestoryObject:<" << _hex(_DestoryObject) << ">\n");

        // 枚举所有命令
        drvname = spaceName;
        drvname += "LookUp";
        _LookUp = loader.Get<DLL_FUNCTION(LookUp)>(drvname.c_str());
        LOGGER(_log << "SpaceName:<" << drvname << ">\n");
        LOGGER(_log << "LookUp:<" << _hex(_LookUp) << ">\n");

        if(_LookUp == NULL)
        {
            LOGGER(_log.WriteLine("LookUp is NULL."));
            return false;
        }

        /* 创建对象 */
        _hInstance = _CreateObject();
        LOGGER(_log << "HInstance:<" << _hInstance << ">\n");

        if(_hInstance < 1)
        {
            LOGGER(_log.WriteLine("创建对象句柄失败"));
            return false;
        }

        StringArguments arg;
        StringArguments rlt;

        string key;
        string val;
        ComplexCommand* pCmd = NULL;
        Ref<ComplexCommand> complexCmd;

        /* 使用LookUp查找EnumCommand命令 */
        pCmd = _LookUp(_hInstance, "EnumCommand");
        if(pCmd == NULL)
        {
            LOGGER(_log.WriteLine("LookUp EnumCommand Failed"));
            return false;
        }
        complexCmd = (*pCmd);
        if(complexCmd.IsNull())
        {
            LOGGER(_log.WriteLine("EnumCommand is Null"));
            return false;
        }
        if(!complexCmd->OnCommand(arg, rlt))
        {
            LOGGER(_log.WriteLine("Run EnumCommand Failed"));
            return false;
        }

        StringArguments::EnumeratorType enumer = rlt.GetEnumerator();
        while(enumer.MoveNext())
        {
            key = enumer.Current().Key;
            val = enumer.Current().Value;

            if(!StringConvert::Compare(key.c_str(), "Cmd", true))
                continue;
            pCmd = _LookUp(_hInstance, val.c_str());
            if(pCmd == NULL)
                continue;
            complexCmd = (*pCmd);
            if(complexCmd.IsNull())
                continue;
            Registe(complexCmd);
            LOGGER(_log << "Cache Command:" << _hex_num(pCmd) << endl;
            complexCmd->Print(_log);
            _log.WriteLine());
        }
        _drv = loader;
        return true;
    }
    bool IsValid()
    {
        return _drv.IsValid();
    }
    void Dispose()
    {
        LOG_FUNC_NAME();
        CommandCollection::Clear();

        if(_hInstance != 0 && _DestoryObject != NULL)
        {
            _DestoryObject(_hInstance);
        }
        _CreateObject = NULL;
        _DestoryObject = NULL;
        _LookUp = NULL;

        _drv.Free();
        _hInstance = 0;
    }
};
//--------------------------------------------------------- 
/// 从动态库中加载的驱动
template<class TArgParser>
class DynamicLibraryCmdDriver : 
    public CommandCollection,
    public LoggerBehavior
{
protected:
    LoggerSetter _logSetter;
    CommandDriverInvoker _drvInvoker;
    CommandDriverToCollectionAdapter<TArgParser> _drvCollection;
    CommandCollectionInvoker _cmdInvoker;
public:
    DynamicLibraryCmdDriver()
    {
        LOGGER(_logSetter.select(_drvInvoker);
        _logSetter.select(_cmdInvoker));
    }
    virtual ~DynamicLibraryCmdDriver()
    {
        Dispose();
    }
    LC_LOGGER_INVOKE(_logSetter);
    bool Load(const char* drv, const char* entryPoint)
    {
        LOG_FUNC_NAME();
        Dispose();
        list_t<Ref<ComplexCommand> > cmdlist;
        bool bLoad = _cmdInvoker.Load(drv, entryPoint);
        LOGGER(_log << "Load CollectionInvoker:<" << bLoad << ">\n");
        if(!bLoad)
        {
            bLoad = _drvInvoker.Load(drv, entryPoint);
            LOGGER(_log << "Load DriverInvoker:<" << bLoad << ">\n");
            if(bLoad)
            {
                _drvCollection.ReleaseDevice();
                _drvCollection.SelectDevice(_drvInvoker);

                _drvCollection.GetCommand("", cmdlist);
            }
        }
        else
        {
            _cmdInvoker.GetCommand("", cmdlist);
        }
        LOGGER(_log.WriteLine("Load ComplexCommands:");
        list_t<Ref<ComplexCommand> >::iterator itr;
        for(itr = cmdlist.begin();itr != cmdlist.end(); ++itr)
        {
            (*itr)->Print(_log);
        });
        CommandCollection::RegisteCommand(*this, cmdlist);
        return _logRetValue(bLoad);
    }
    void Dispose()
    {
        CommandCollection::Clear();

        _drvInvoker.Dispose();
        _cmdInvoker.Dispose();
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_DYNAMICLIBRARYCMDDRIVER_H_
//========================================================= 